using System;
using System.Collections.Generic;
using System.Text;

using NSimpleDB.Service.Contract;

namespace NSimpleDB.Service.VistaDb.Resultsets
{
    //TODO: add isolated unit tests for resultsetpagebuffer
    internal class ResultsetPageBuffer
    {
        private readonly TimeSpan maxPageLifetime = new TimeSpan(0, 0, 0, 2);

        private Dictionary<string, ResultsetPage> pages;
        private DateTime lastGCRunAt;


        public ResultsetPageBuffer()
        {
            this.pages = new Dictionary<string, ResultsetPage>();
            this.lastGCRunAt = DateTime.Now;
        }


        public PagedResultset CreatePagedResultset(int pageSize)
        {
            this.GarbageCollectPages();

            return new PagedResultset(pageSize);
        }


        public void AddResultset(PagedResultset rs)
        {
            lock (this.pages)
            {
                if (rs.Pages.Count > 0 && rs.Pages[0].results.Count > 0)
                    foreach (ResultsetPage p in rs.Pages)
                        this.pages.Add(p.token, p);
            }
        }


        public string[] GetResultsetPage(string token, out string nextToken)
        {
            lock (this.pages)
            {
                ResultsetPage page;
                if (this.pages.TryGetValue(token, out page))
                {
                    this.pages.Remove(token);
                    nextToken = page.nextToken;
                    return page.results.ToArray();
                }
                else
                {
                    nextToken = null;
                    return null;
                }
            }
        }


        private void GarbageCollectPages()
        {
            lock (this.pages)
            {
                if (DateTime.Now.Subtract(this.lastGCRunAt) > this.maxPageLifetime)
                {
                    List<string> pageTokens = new List<string>(this.pages.Keys);
                    foreach (string token in pageTokens)
                    {
                        ResultsetPage p = this.pages[token];
                        if (DateTime.Now.Subtract(p.createdAt) > this.maxPageLifetime)
                            this.pages.Remove(token);
                    }

                    this.lastGCRunAt = DateTime.Now;
                }
            }
        }
    }
}
